/*
 * =====================================================================================
 *
 *       Filename:  proc_mod.c
 *
 *    Description:  实现自己的/proc文件的实验
 *    实现自己的一个/proc文件，文件要求：
 *    1.向该proc文件写入pid时，返回该pid对应的执行程序名称
 *    2.向该proc文件读取时，返回之前的查看记录
 *
 *        Version:  1.0
 *        Created:  2015年09月16日 13时35分09秒
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  YOUR NAME (), 
 *   Organization:  
 *
 * =====================================================================================
 */
#include <linux/module.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
#include <linux/sched.h>



MODULE_AUTHOR("guicai.ma@qq.com");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("create a /proc file");

#define MAX_LENGTH  64
#define MAX_RECORD  5
#define F_NAME  "pid"
#define D_NAME  "magc"
#define P_NAME  "/proc/" D_NAME "/" F_NAME

/**
 * @brief 定义一个包含PID和描述内容的结构体
 */
typedef struct {
    pid_t pid;
    char comm[TASK_COMM_LEN]; 
}pidcomm_t; 
static int bufpos =0;
pidcomm_t podcommBuf[MAX_RECORD];

static struct proc_dir_entry *pid_entry;
static struct proc_dir_entry *dir_entry;

pidcomm_t pidcommBuf[MAX_RECORD];

/**
 * @brief 实现写回调函数过程
 *
 * @param file
 * @param buffer
 * @param count
 * @param data
 *
 * @return 
 */
static int pid_write(struct file *file,const char __user *buffer , unsigned long count,void *data){
    struct task_struct *_process;
    char pid_buffer[MAX_LENGTH];
    unsigned long pid_buffer_size = count;
    if(pid_buffer_size >MAX_LENGTH)
        pid_buffer_size = MAX_LENGTH;
    memset(pid_buffer,0,MAX_LENGTH);
    if(copy_from_user(pid_buffer,buffer,pid_buffer_size))
        return -EFAULT;
    //遍历task
    for_each_process(_process){
        char _tmp[MAX_LENGTH];
        sprintf(_tmp,"%d\n",_process->pid);
        if(!strcmp(_tmp,pid_buffer)){
            printk("<1> the EXE file is %20s \n ",_process->comm);
            pidcommBuf[bufpos].pid = _process->pid;
           memset(pidcommBuf[bufpos].comm,0,TASK_COMM_LEN);
          strcpy(pidcommBuf[bufpos].comm,_process->comm);
         bufpos = bufpos==MAX_RECORD-1?0:bufpos+1; 
        }
    }
    return pid_buffer_size;

}

/**
 * @brief 实现读回调函数过程
 *
 * @param page
 * @param start
 * @param off
 * @param count
 * @param eof
 * @param data
 *
 * @return 
 */
static int pid_read(char *page,char **start,off_t off,int count,int *eof,void *data){

    int i,ret,len=0;

   char *pos = page;

  if(off>0){
      *eof = 1;
      return 0;
  } 
  ret = sprintf(pos,"PID\tCOMMAND\n");
 len += ret;
 pos += ret;
 for (i = 0; i < MAX_LENGTH; ++i) {
    if(0==pidcommBuf[i].pid)
       break;
    ret = sprintf(pos,"%d\t%s\n",pidcommBuf[i].pid,pidcommBuf[i].comm);
    len += ret;
    pos += ret; 
     
 }
 return len;
 

}

/**
 * @brief 模块初始化
 *
 * @return 
 */
static int __init proc_init(void)
{
    dir_entry= proc_mkdir(D_NAME,NULL);
    if(!dir_entry){
        printk(KERN_ERR "Can't create /proc/" D_NAME "\n");
        return -ENOMEM;
    }

    printk("<1> create " D_NAME "Successfully\n" );

    pid_entry = create_proc_entry(F_NAME,0666,dir_entry);
    if(!pid_entry){
        remove_proc_entry(F_NAME,dir_entry);
        printk(KERN_ERR F_NAME" create failed\n");
        return -ENOMEM;
    }
    pid_entry->read_proc = pid_read;
    pid_entry->write_proc = pid_write;
    printk("<1> create " F_NAME "Successfully\n" );

    return 0;
}

/**
 * @brief 模块卸载
 *
 * @return 
 */
static void __exit proc_exit(void)
{

    remove_proc_entry(F_NAME,dir_entry);
    printk("<1> delete " F_NAME "Successfully\n" );

    remove_proc_entry(D_NAME,NULL);
    printk("<1> delete " D_NAME "Successfully\n" );
    printk("<1> Exit \n");
}
module_init(proc_init);
module_exit(proc_exit);
